#pragma once
#include <iostream>
#include <memory>
#include "Socket.hpp"
#include "InetAddr.hpp"
#include <jsoncpp/json/json.h>
#include <functional>
using namespace SocketModule;
// 实现一个自定义的网络版本计算器
// 约定好各个字段的含义，本质就是约定好协议
// client->serve
class Request
{
    // 都需要序列和反序列化接口
public:
    Request() {}
    Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper) {}
    // 序列化，这里的数据是需要发送给服务器的
    std::string Serialization()
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;
        Json::FastWriter write;
        std::string s = write.write(root);
        return s;
    }
    bool DeSerialization(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (!ok)
            return ok;
        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();

        return ok;
    }
    int GetX() { return _x; }
    int GetY() { return _y; }
    char GetOper() { return _oper; }
    ~Request() {}

private:
    int _x;
    int _y;
    char _oper;
};

// serve->client
class Response
{
    // 只有运算结果，无法区分应答是否计算成功
public:
    Response() {}
    Response(int code) : _code(code) {}
    Response(int result, int code) : _result(result), _code(code) {}
    ~Response() {}
    std::string Serialization()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;
        Json::FastWriter write;
        std::string s = write.write(root);
        return s;
    }
    bool DeSerialization(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (!ok)
            return ok;
        _result = root["result"].asInt();
        _code = root["code"].asInt();

        return ok;
    }
    void ShowResult()
    {
        std::cout << "计算的结果是: " << _result << "[" << _code << "]" << std::endl;
    }
    void Setres(int _res) { _result = _res; }
    void Setcode(int code) { _code = code; }

private:
    int _result;
    int _code; // 0表示计算正确
};

using func_t = std::function<Response(Request &req)>;
class Protocol
{
public:
    Protocol() {}
    Protocol(func_t func) : _func(func) {}
    // TCp是面向字节流的，每次从缓冲区中读数据可能会读的不是一条完整的报文，可能是一条或者多条，又或者不足一条
    // 为了解决这种情况，我们可以在一条报文的前后增加一些标志位来标识报文的开头和结束以及报文长度
    // 增加了报头，到时候还需要解报，所以需要设计成易于封装和解封装
    // 增加两个接口，一个用于封装，一个用于解封装
    // 下面约定20\r\n{"x":10,"y":20:"oper":"+"}\r\n是一条完整的报文
    const std::string sep = "\r\n";
    std::string EncauplationMessage(std::string Message)
    {
        // 封装报文
        size_t len_message = Message.size();
        return std::to_string(len_message) + sep + Message + sep;
    }
    // 读取到的一条报文有多种可能，我们只需要做的就是提取一条有效的报文，提取不到有效报文也不能返回报文，
    // 所以函数设计成返回bool比较合适,参数需要一个被解封装的报文，还有读取成功时返回的一条报文

    // 一条完整的报文
    // 20\r\n{"x":10,"y":20:"oper":"+"}\r\n
    // 参数设计成string*还是string，看具体实现在修改吧,
    // 参数设计成string*，因为这些数据都是在缓冲区里的，如果想要修改必须传址，传值不会对package有影响
    // 自然这个函数的逻辑实现也就没有作用
    // 通过telent+ip连接
    bool ReleaseEncauplationMessage(std::string &Message, std::string *package)
    {
        // 查找sep的位置，如果sep不存在，一定不是一条完整的报文
        size_t sep_position = Message.find(sep);
        if (sep_position == std::string::npos)
            return false;
        // 找报文长度
        std::string Message_len = Message.substr(0, sep_position);
        // 读取并计算一条完整报文应有的长度
        int target_len = std::stoi(Message_len) + Message_len.size() + sep.size() * 2;
        // 实际读到的报文长度如果还没有应有长度大就证明没有读到一条完整的报文
        if (target_len > Message.size())
            return false;

        // 返回读到的一条报文
        *package = Message.substr(sep_position + sep.size(), std::stoi(Message_len));
        // 删除刚才读到的报文
        Message.erase(0, target_len);
        return true;
    }
    // 一直死循环打印accept unsuccess不是这里的问题
    // 是Start函数里处理sockfd的问题
    std::string GetRequest(std::string &Message)
    {
        LogModule::LOG(DEBUG) << "进入了 Protocal::GetRequest(std::string)";

        Request AnalysisJson;
        bool ok = AnalysisJson.DeSerialization(Message);
        if (!ok)
            return std::string();

        Response resp = _func(AnalysisJson);
        std::string SerialRecvEcho = resp.Serialization();

        std::string EncauplationJson = EncauplationMessage(SerialRecvEcho);

        LogModule::LOG(DEBUG) << "结束了 Protocal::GetRequest(std::string)";
        return EncauplationJson;
    }

    std::string BuildRequestString(int x, int y, char oper)
    {
        // 1.序列化字符串
        Request req(x, y, oper);
        std::string req_str = req.Serialization();
        // 2.封装字符串
        //  std::cout<<"------req_str--------"<<std::endl;
        //  std::cout<<req_str<<std::endl;
        //  std::cout<<"---------------------"<<std::endl;
        return EncauplationMessage(req_str);
    }
    bool GetResponse(std::unique_ptr<Socket> &client, std::string &res_buffer, Response *res)
    {
        while (true)
        {
            // 先通过sockfd获取request
            int n = client->Recv(&res_buffer);
            if (n > 0)
            {
                // 响应的一定是一个序列化的串，需要先解报
                std::string REMessage;
                while (ReleaseEncauplationMessage(res_buffer, &REMessage))
                {
                    // std::cout<<"------解报后的字符串REMessage--------------"<<std::endl;
                    // std::cout<<REMessage<<std::endl;
                    // std::cout<<"-----------------------------------"<<std::endl;
                    // if(!ok)
                    //     continue;
                    res->DeSerialization(REMessage);
                    // std::cout<<"------反序列化后的字符串REMessage--------------"<<std::endl;
                    // std::cout<<REMessage<<std::endl;
                    // std::cout<<"-----------------------------------"<<std::endl;
                    return true;
                }
            }
            else if (n == 0)
            {
                LOG(WARNING) << "Serve" << " QUIT";
                // break;
                return false;
            }
            else
            {
                LOG(WARNING) << "Serve Recv" << " error";
                // break;
                return false;
            }
        }
    }
    ~Protocol() {}

private:
    // 多线程使用临时变量
    //  Request _requ;
    //  Response _resp;
    func_t _func;
};